/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Validation;

import Builder.Scorer;
import DAO.DAOAccess;
import DAO.DAOHelper;
import DAO.InformationFilter.PageDAO;
import DAO.InformationFilter.UserDAO;
import DataModel.ArrDataModel;
import DataModel.DataModel;
import Info.PageInfo;
import MySqlAccess.*;
import Recommender.Collarative_Filtering.Collarative_filtering;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

/**
 *
 * @author tran tuan tai
 */
public class Validate {

    List<RatingInfo> m_lstTrain;
    List<RatingInfo> m_lstTest;
    HashMap<Integer, List<RatingInfo>> m_lstFold;
    int m_numFold = 10;
    Scorer score = new Scorer();

    private void CreateFold()
    {
        UserRating rating = new UserRating();
        List<RatingInfo> lstRatingInfo = rating.GetAllItem();
        int sizeYetRating = lstRatingInfo.size();

        List<RatingInfo> lstNotRating = new ArrayList<RatingInfo>();

        PageDAO pageDAO = new PageDAO();
        UserDAO userDAO = new UserDAO();

        List<PageInfo> allPage = pageDAO.GetAll();
        List<Info.UserInfo> allUser = userDAO.GetAll();

        int iLoop = 0, idxPage, idxUser, sizePage = allPage.size(), sizeUser = allUser.size();
        int boundRatingSize= 200 + sizeYetRating;
        Random random = new Random();
        while(lstNotRating.size() < sizeYetRating && iLoop < boundRatingSize)
        {
            iLoop++;
            idxPage = random.nextInt(sizePage);
            idxUser = random.nextInt(sizeUser);

            boolean notYet = true;
            for (RatingInfo ri : lstNotRating)
            {
                if (ri.m_idItem == idxPage && ri.m_idUser == idxUser)
                {
                    notYet = false;
                    break;
                }
            }

            if (notYet)
            {
                boolean isRating = false;
                for (int i = 0; i < sizeYetRating; i++)
                {
                    if (lstRatingInfo.get(i).m_idItem == idxPage && lstRatingInfo.get(i).m_idUser == idxUser)
                    {
                        isRating = true;
                        break;
                    }
                }

                if (!isRating)
                {
                    RatingInfo nRating = new RatingInfo();
                    
                    nRating.m_idUser = idxUser;
                    nRating.m_idItem = idxPage;
                    nRating.m_rating = 0;
                    nRating.m_dateTime = new Date();

                    lstNotRating.add(nRating);
                }
            }
        }

        List<RatingInfo> lstUsing = new ArrayList<RatingInfo>();
        lstUsing.addAll(lstRatingInfo);
        lstUsing.addAll(lstNotRating);
        Collections.shuffle(lstUsing);

        int size = lstUsing.size();
        int itemPerFold = size / m_numFold;

        m_lstFold = new HashMap<Integer, List<RatingInfo>>();

        int nFoldLess1 = m_numFold - 1;
        int idxItem = 0;
        for (int i = 0; i < nFoldLess1; i++) {
            int bound = idxItem + itemPerFold;
            List<RatingInfo> fold = new ArrayList<RatingInfo>();
            for (;idxItem < bound; idxItem++)
            {
                fold.add(lstUsing.get(idxItem));
            }

            m_lstFold.put(i, fold);
        }

        List<RatingInfo> fold = new ArrayList<RatingInfo>();
        for (; idxItem < size; idxItem++) {
            fold.add(lstUsing.get(idxItem));
        }
        m_lstFold.put(m_numFold - 1, fold);
    }

    private void CreateFold_Random()
    {
        PageDAO pageDAO = new PageDAO();
        UserDAO userDAO = new UserDAO();

        List<PageInfo> allPage = pageDAO.GetAll();
        List<Info.UserInfo> allUser = userDAO.GetAll();

        Random random = new Random();

    }

    public void Validate() {
        CreateFold();

        List<DataModel> lstTrainDataModel = new ArrayList<DataModel>();
        List<DataModel> lstTestDataModel = new ArrayList<DataModel>();

        for (int idxTest = 0; idxTest < m_numFold; idxTest++) {
            //if (idxTest == 0) continue;
            for (int idxFold = 0; idxFold < m_numFold; idxFold++) {
                if (idxFold != idxTest) {
                    List<RatingInfo> lstRating = m_lstFold.get(idxFold);
                    for (RatingInfo ratingInfo : lstRating) {
                        DataModel dm = new DataModel(ratingInfo.m_idUser, ratingInfo.m_idItem,
                                ratingInfo.m_rating, (int) ratingInfo.m_dateTime.getTime());
                        lstTrainDataModel.add(dm);
                    }
                } else {
                    List<RatingInfo> lstRating = m_lstFold.get(idxFold);
                    for (RatingInfo ratingInfo : lstRating) {
                        DataModel dm = new DataModel(ratingInfo.m_idUser, ratingInfo.m_idItem,
                                ratingInfo.m_rating, (int) ratingInfo.m_dateTime.getTime());
                        lstTestDataModel.add(dm);
                    }
                }
            }

            Collarative_filtering cf = new Collarative_filtering();

            DataModel[] arrDM = new DataModel[lstTestDataModel.size()];
            int sizeDM = lstTestDataModel.size()
                    ;
            for (int i = 0; i < sizeDM; i++) {
                arrDM[i] = lstTestDataModel.get(i);
            }

            ArrDataModel arrtest = new ArrDataModel(lstTestDataModel.size(), arrDM);

            arrDM = new DataModel[lstTrainDataModel.size()];
            sizeDM = lstTrainDataModel.size();
            for (int i = 0; i < sizeDM; i++) {
                arrDM[i] = lstTrainDataModel.get(i);
            }

            ArrDataModel arr = new ArrDataModel(lstTrainDataModel.size(), arrDM);
            arrtest.GetNumOFItem();
            arrtest.GetNumOFUser();

            try {
                cf.Init_CF(arr);
                cf.GetPoint_CF(sizeDM, sizeDM, arr, sizeDM, sizeDM, sizeDM);
               cf.TestCF(arr, arrtest);
               /*for (int k = 0; k < 1000; k++) {
                    System.out.println(cf.GetPoint_CF(lstTest.get(k).GetIDUser(), lstTest.get(k).GetIDItem(), arr, 0.4f, 0.3f, 0.3f));
                }*/
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public  void ContentValidation()
    {
        CreateFold();

        int totalCorrect = 0;
        Scorer score = new Scorer();

        List<DataModel> lstTrainDataModel = new ArrayList<DataModel>();
        List<DataModel> lstTestDataModel = new ArrayList<DataModel>();

        double rmaeCollarative = 0;
        double maeCollarative = 0;
        double maeContent = 0;
        double rmaeContent = 0;

        double mae = 0, rmae = 0;

        for (int idxTest = 0; idxTest < m_numFold; idxTest++)
        {
            for (int idxFold = 0; idxFold < m_numFold; idxFold++)
            {
                if (idxFold != idxTest)
                {
                    List<RatingInfo> lstRating = m_lstFold.get(idxFold);
                    for (RatingInfo ratingInfo : lstRating) {
                        DataModel dm = new DataModel(ratingInfo.m_idUser, ratingInfo.m_idItem,
                                ratingInfo.m_rating, (int) ratingInfo.m_dateTime.getTime());
                        lstTrainDataModel.add(dm);
                    }
                } else {
                    List<RatingInfo> lstRating = m_lstFold.get(idxFold);
                    for (RatingInfo ratingInfo : lstRating) {
                        DataModel dm = new DataModel(ratingInfo.m_idUser, ratingInfo.m_idItem,
                                ratingInfo.m_rating, (int) ratingInfo.m_dateTime.getTime());
                        lstTestDataModel.add(dm);
                    }
                }
            }

            Collarative_filtering cf = new Collarative_filtering();

            DataModel[] arrDM = new DataModel[lstTestDataModel.size()];
            int sizeDM = lstTestDataModel.size()
                    ;
            for (int i = 0; i < sizeDM; i++) {
                arrDM[i] = lstTestDataModel.get(i);
            }

            ArrDataModel arrtest = new ArrDataModel(lstTestDataModel.size(), arrDM);

            arrDM = new DataModel[lstTrainDataModel.size()];
            sizeDM = lstTrainDataModel.size();
            for (int i = 0; i < sizeDM; i++) {
                arrDM[i] = lstTrainDataModel.get(i);
            }

            ArrDataModel arr = new ArrDataModel(lstTrainDataModel.size(), arrDM);
            arrtest.GetNumOFItem();
            arrtest.GetNumOFUser();

            List<RatingInfo> lstTestRatingInfo = m_lstFold.get(idxTest);

            try
            {
                cf.Init_CF(arr);
                int incorrectContent = 0, incorrectCollarative = 0;
                int sizeTest = lstTestRatingInfo.size();

                int incorrect = 0;
                for (RatingInfo ratingInfo : lstTestRatingInfo)
                {
                    Double iScoreContent = score.GetScorer(ratingInfo.m_idUser, ratingInfo.m_idItem);

                    float iScoreCollative = cf.GetPoint_CF(ratingInfo.m_idUser, ratingInfo.m_idItem
                            , arr, 0.4f, 0.3f, 0.3f);
                    int iscore = 0;

                    if (iScoreContent == null)
                    {
                        sizeTest--;
                    }
                    else
                    {
                        if (iScoreCollative * iScoreContent > 0)
                        {
                            iscore = 1;
                        }

                       if (iscore != ratingInfo.m_rating)
                        {
                            incorrect++;
                        }                       
                    }
                }
                    mae += incorrect*1.0/sizeTest;
                    rmae += Math.sqrt(incorrect*1.0/sizeTest);

                   
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }

            
        }

            mae /= m_numFold;
            rmae /= m_numFold;

            System.out.println("######## Result");
            System.out.println(mae);
            System.out.println(rmae);
    }
    public static void main(String[] argvs) {

        DAOAccess.SetServer(argvs[0]);
        DAOAccess.SetUser(argvs[1]);
        DAOAccess.SetPass(argvs[2]);
        DAOAccess.CreateConnection();

        DataAcessHelper.SetServer(argvs[0]);
        DataAcessHelper.SetUser(argvs[1]);
        DataAcessHelper.SetPass(argvs[2]);
        DataAcessHelper.CreateConnection();

        DAOHelper.SetServer(argvs[0]);
        DAOHelper.SetUser(argvs[1]);
        DAOHelper.SetPass(argvs[2]);
        DataAcessHelper.CreateConnection();
        
        Validate val = new Validate();
        val.ContentValidation();
    }
}
